Girder COM
The
addition of LuaCOM extensions opens a
whole new world to Girder. Component
Object Model (COM) is a specification that enables the creation of software
components that are language and location independent. It is a Microsoft technology that is also
includes other terms such as OLE, DCOM and ActiveX. This allows Girder to use software components
to develop more sophisticated applications.
Girder can use COM objects to retrieve information from many sources, to
interact with users, to receive events from objects, and to control other
applications. Any user of Visual Basic,
C, VBScript, or WScript will likely be familiar with
COM. Using COM objects in Lua is very similar to the WScript
and VBScript languages. .
The LuaCOM homepage is
http://www.tecgraf.puc-rio.br/~rcerq/luacom/. Documentation is available online from this
page.
Useful resources on MSDN:
MSDN (Microsoft Developer Network): http://msdn.microsoft.com/
COM: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/registry_6lrr.asp
FileSystemObject: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/jsfsotutor.asp
WindowsScriptingHost: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/jsfsotutor.asp
Scripting Guide: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnclinic/html/scripting01142003.asp
Windows Management and Instrumentation: http://msdn.microsoft.com/library/en-us/dnanchor/html/anch_wmi.asp
Managing Windows with WMI: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmi/html/mngwmi.asp
XML Core Services: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/htm/dom_starter_0h7x.asp
WinHTTP: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winhttp/http/winhttp_reference.asp
Other resources:
Win32 Scripting Tools: http://cwashington.netreach.net/main/tools
The Windows Scripting Guide: http://www.winguides.com/scripting/
Replace
API Calls Using WMI: http://www.fawcette.com/Archives/premier/mgznarch/vbpj/2000/09sep00/kg0009/kg0009.asp
Fops
ActiveX Control: http://www.softuarium.com/fops.htm
ActiveX Components (free): http://www.sevillaonline.com/ActiveX/
Loading LuaCOM
The LuaCOM library must be loaded before use. This is accomplished by using the following
statement:
LoadLuaCom ()
This
function returns 0 or > if successful.
Using LuaCOM
To program
using ActiveX and COM objects requires some understanding of how they
work. In short, objects are initialized,
then used and then disposed of before the program terminates. Objects are created using the:
MyObject = luacom.CreateObject
(“MyObject.Object”) or
MyObject = luacom.GetObject (MyObject.Object”) functions.
These
functions return a table value which is the interface to the object.
Object
properties are retrieved using the following syntax:
MyObject.value
Methods are
executed using in a similar fashion but with colon “:” not a period “.”
MyObject:method ()
Objects
that generate events can also be used. See example 7 below for how to create an event handler. Objects are enumerated differently then in
VBScript or WScript.
See example 2 for how to enumerate WMI objects.
It is
imperative that objects be disposed of properly. So when you are finished with an object:
MyObject = nil
Collectgarbage ()
Lastly, the
Girder programming environment allows you to make changes to the code while it
is running. In most instances, this fine
but when using LuaCOM, this can lead to a Girder
crash. To avoid this, you must not
change your program until you have disposed of all objects. This particularly true when
using event handlers. To deal
with this, Girder 3.3 now includes a BeforeScriptReset
event. This event occurs when the F11
key is pressed (Reset Script). This
event and the OnGirderClose event should be linked to
a section of Lua code the makes sure any existing
objects are properly disposed of.
Closing LuaCOM
The LuaCOM library should be closed when a program
finishes. It does not need to be closed
after each use, just prior to Girder exiting.
The command is:
UnloadLuaCom ()
This is
easily done by linking the OnGirderClose event to the
above Lua code.
Examples
1.
FileSystemObject.
See the MSDN reference for object details.
fso = luacom.CreateObject
("Scripting.FileSystemObject")
fso:FileExists
("\\\\C:\\test.txt") == 1 then
print (“File
Exists.”)
end
fso = nil
collectgarbage ()
Notes: In Lua, the “\” is an escape character and double “\\” equal
one “\”. COM Objects use the C
conventions for true and false (1,0) where as LUA uses
non-nil and nil.
2.
Windows Management and Instrumentation.
WMI is a very powerful way to monitor and control Windows 2000 and
greater computers. It is not easy to
understand and using it will require a significant amount of reading on
MSDN. Here is an example that enumerates
all the hard drives on a system and saves that information in a text file.
fs = luacom.CreateObject("Scripting.FileSystemObject")
outFile = fs:CreateTextFile("c:\\harddrive.txt",
1)
diskdrives = luacom.GetObject("winmgmts:{impersonationLevel=impersonate}"):InstancesOf("Win32_DiskDrive")
diskdrives_en = luacom.GetEnumerator(diskdrives)
Item = diskdrives_en:Next()
while Item do
outFile:WriteLine("Caption: "..Item:Caption())
outFile:WriteLine("Description: "..Item:Description())
outFile:WriteLine("InterfaceType:
"..Item:InterfaceType())
outFile:WriteLine("Manufacturer: "..Item:Manufacturer())
outFile:WriteLine("Partitions: "..Item:Partitions())
outFile:WriteLine("ScsiBus:
"..Item:ScsiBus())
outFile:WriteLine("ScsiTargetID:
"..Item:ScsiTargetID())
outFile:WriteLine("Size: "..Item:Size())
outFile:WriteLine("")
Item = diskdrives_en:Next()
end
outFile:Close()
fs = nil
diskdrives = nil
diskdrives_en = nil
collectgarbage ()
3. DOM
(Document Object Model) and XML for retrieving data from CoolMon
(http://coolmon.arsware.org/)
DOM
= luacom_CreateObject("Msxml2.DOMDocument")
DOM.async = 0
DOM:load
("http://localhost:61300")
proc = DOM:selectSingleNode ("CoolMon/Raw/Processor_Usage")
DOM
= nil
collectgarbage ()
print ("Processor Usage: ",proc.text)
4. Windows
Scripting Host – Popup Message
function PopupMessage (Text,SecondsToWait,Title,Type)
--
see MSDN Wscript.Shell Popup for documentation
local WshShell,x
WshShell = luacom_CreateObject("WScript.Shell")
x = WshShell:Popup(Text,SecondsToWait,Title,Type)
WshShell = nil
collectgarbage
()
return x
end
PopupMessage ("Welcome to LuaCOM”,
20, "Girder", 64)
5. Using
WMI to start a process.
function WMICreateProcess (strComputer,Process)
local objWMIService,objProcess,result
strComputer
= strComputer or "."
objWMIService
= luacom.GetObject ( "winmgmts:{impersonationLevel=Impersonate}!\\\\" ..strComputer.."\\root\\cimv2")
objProcess
= objWMIService:Get("Win32_Process")
result = objProcess:Create (Process,nil,nil,nil)
objProcess
= nil
objWMIService
= nil
collectgarbage
()
return result
end
WMICreateProcess (".","NotePad.exe")
6. Get
Computer Name using WSH
function GetComputerName
()
local
WshNetwork,x
WshNetwork
= luacom_CreateObject("WScript.Network")
x = WshNetwork.ComputerName
WshNetwork
= nil
collectgarbage ()
return
x
end
print (GetComputerName())
7. Below is
a complete example of using LuaCOM with CoolMon. This
example uses asynchronous retrieval of CoolMon data
by connecting an event handler with the DOM object.
--
CoolMon system information retrieval
--
retrieves data from CoomMon via its web service
--
can retreive data from any machine on the network
--
requires coolmon v2
--
retrieves data async, use luacom
events!
function CoolMonInit ()
CoolMon = {} --
table of CM DOMs,Data
print ("CoolMon Initialized")
end
function CoolMonDisconnect
()
local i,j
for i,j in CoolMon do
CoolMon [i].DOM= nil
end
collectgarbage
()
end
CoolMonEvent = {}
function CoolMonEvent:onreadystatechange ()
local i,j
for i,j in CoolMon do
if CoolMon [i].pendingload
and CoolMon [i].DOM.readyState == 4 then -- dom
is loaded
CoolMonDataReady
(i)
end
end
end
function CoolMonAddLocation
(url,async,datareadyevent)
--
create XML DOM object
--
async, 0 = no, 1 = yes, if a remote connection, probably should use async connections ...
--
datareadyevent - event to
call when new data has been received
--
title = name of resource
CoolMon [url] = {}
CoolMon [url].DOM = luacom_CreateObject("Msxml2.DOMDocument")
CoolMon [url].DOM.async = 1--async or 1 -- allow async as default
CoolMon [url].datareadyevent
= datareadyevent
CoolMon [url].pendingload
= nil -- non nil when waiting for return event
CoolMon [url].data = {} -- retrieved data
if not luacom_Connect(CoolMon [url].DOM,CoolMonEvent) then
--link event handler
print ("CoolMon: Unable to connect onreadystatechange")
else
print ("CoolMon: ",url,"
added.")
end
end
function CoolMonLoadData (url)
--
load data from coolmon
if CoolMon [url].DOM.readyState
== 4 then -- do not call to load data if
previous load operation not complete
CoolMon [url].pendingload
= 0 -- for event handler below
return CoolMon [url].DOM:load
(url)
end
end
function CoolMonDataReady (url)
--
get data
local startingnode
CoolMon [url].pendingload
= nil
if CoolMon [url].DOM.readyState
== 4 then -- dom is loaded
startingnode
= CoolMon [url].DOM:selectSingleNode ("CoolMon")
if CoolMon [url].DOM.parseError.errorCode
~= 0 then -- error parsing/retrieving
CoolMon [url].data = {}
CoolMon [url].data ["Error Code"]
= CoolMon [url].DOM.parseError.errorCode
CoolMon [url].data ["Reason"] = CoolMon [url].DOM.parseError.reason
else
CoolMon [url].data = CoolMonDatatoTable
(startingnode, 0)
end
if CoolMon [url].datareadyevent
then
CoolMon [url].datareadyevent
(url)
end
end
end
function CoolMonDatatoTable
(StartNode)
--
parse CoolMon XML data into a table
--
this is the quick and dirty but done this way for
speed.
local i,t,dn,nl,xNode
t = {}
dn
= StartNode:selectSingleNode ("Raw")
if dn:hasChildNodes () > 0 then
nl
= dn.childNodes
for i = 0, nl.length - 1 do
xNode
= nl:item (i)
t [xNode.nodeName] = xNode.text
end
end
dn
= StartNode:selectSingleNode ("Formatted")
if dn:hasChildNodes () > 0 then
nl
= dn.childNodes
for i = 0, nl.length - 1 do
xNode
= nl:item (i)
if strfind (xNode.text,":")
then
t [strsub (xNode.text,1,strfind (xNode.text,":")
-1)] = strsub (xNode.text,strfind
(xNode.text,":") +1,-1)
end
end
end
return t
end
function CoolMonDataPrint
(data)
local k,v
for k,v in data do
print
("Index: "..k.." Value: "..v)
end
end
The
above examples just give a token idea of what can be done with LuaCOM.
Girder COM Object
Girder
provides an COM object to allow other programs to
directly send events to Girder. Here is
an example from WScript.
GirderEvent = WScript.CreateObject("Girder.GirderEvent");
GirderEvent.Device = 18;
GirderEvent.EventString = "MyEvent";
GirderEvent.Payload(1) = payload;
GirderEvent.Send();